﻿/*
-----------------------------------------------------------------------------
This source file is part of Cell Cloud.

Copyright (c) 2009-2012 Cell Cloud Team - cellcloudproject@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#ifndef CellPacket_h
#define CellPacket_h

#include "CellPrerequisites.h"

namespace cell
{
/** \addtogroup Core
 *  @{
 */
/** \addtogroup General
 *  @{
 */

// 包段数据长度定义。
#define PSL_TAG 4
#define PSL_VERSION 4
#define PSL_SN 4
#define PSL_BODY_LENGTH 8
#define PSL_SUBSEGMENT_NUM 4
#define PSL_SUBSEGMENT_LENGTH 8

// 最大包体长度。
#define PACKET_MAX_BODYLENGTH 262144

#define PSL_BODYLENGTH_STRINGLENGTH (PSL_BODY_LENGTH + 1)
#define PSL_SUBSEGMENTNUM_STRINGLENGTH (PSL_SUBSEGMENT_NUM + 1)
#define PSL_SUBSEGMENTLENGTH_STRINGLENGTH (PSL_SUBSEGMENT_LENGTH + 1)

/** 数据包类。描述在网络上进行投递的数据包格式。
@author
	Jiangwei Xu
@remarks
	数据包划分为 Tag（标签）、Version（版本）、Sequence Number（序号）、
	Body Length（包体长度） 和 Body Data（包数据） 等 5 个主要数据段，
	依次简记为：TAG、VER、SEN、LEN、DAT。
	格式如下：<br />
	TAG | VER | SEN | LEN | DAT <br />
	各字段说明如下：<br />
	包标签 | 版本描述 | 包序号 | 包体长度 | 包体数据 <br />
	以上数据格式中，符号'|'表示逻辑分割，不是数据包实体数据的一部分。
	各数据域长度如下（单位：byte）：<br />
	[TAG] - 4 <br />
	[VER] - 4 <br />
	[SEN] - 4 <br />
	[LEN] - 8 <br />
	[DAT] - {!} 由 LEN 决定，最大 262144 bytes。<br />
	Packet 提供了对 DAT 段的动态定义能力。
	依次 DAT 段数据可以进行二次分解，分解为任意长度的子数据段。
	DAT 段数据格式如下：<br />
	SSN | SSL{1} | ... | SSL{n} | SSD{1} | ... | SSD{n} <br />
	个数据字段说明如下： <br />
	段数量 | 段1长度 | ... | 段N长度 | 段1数据 | ... | 段 N 数据 <br />
	各数据域长度如下（单位：byte）：<br />
	[SSN] - 4 <br />
	[SSL] - 8 <br />
	[SSD] - {!} 由 SSL 决定 <br />
	SSL 和 SSD 数据一致，且由 SSN 决定。
*/
class _CellExport Packet : public GeneralAlloc
{
public:
	/** 默认构造函数。
	*/
	Packet(void);

	/** 构造函数。
	*/
	Packet(char* tag, uint16 sn, uint16 major = 1, uint16 minor = 0);
	/** 构造函数。
	*/
	Packet(byte* tag, uint16 sn, uint16 major = 1, uint16 minor = 0);

	/** 构造函数。
	*/
	Packet(char* tag, uint16 sn, char* body, uint length, uint16 major = 1, uint16 minor = 0);

	/** 析构函数。
	*/
	virtual ~Packet(void);

public:
	/** 获取标签。
	*/
	uint16 getTag(char* tag) const;
	/** 获取标签。
	*/
	uint16 getTag(byte* tag) const;

	/** 设置标签。
	*/
	void setTag(const char* tag);
	/** 设置标签。
	*/
	void setTag(const byte* tag);

	/** 比较输入标签是否和该包标签相同。
	*/
	bool compareTag(const char* tag) const;
	/** 比较输入标签是否和该包标签相同。
	*/
	bool compareTag(const byte* tag) const;

	/** 获取包版本号。
	*/
	void getVersion(uint16* major, uint16* minor) const;

	/** 设置包版本号。
	*/
	void setVersion(uint16 major, uint16 minor);

	/** 获取包序列号。
	*/
	void getSequenceNumber(uint16* sn) const;

	/** 设置包序列号。
	*/
	void setSequenceNumber(uint16 sn);

	/** 获取包体数据。
	*/
	uint getBody(byte* body) const;
	/** 获取包体数据。
	*/
	uint getBody(char* body) const;

	/** 返回包体数据长度。
	*/
	inline uint getBodyLength(void) const;

	/** 设置包体数据。
	*/
	uint setBody(const byte* body, const uint length);

	/** 设置包体数据。
	*/
	uint setBody(const char* body, const uint length);

	/** 返回子段数量。
	*/
	uint getSubsegmentNum(void) const;

	/** 返回指定索引处的子段长度。
	*/
	uint getSubsegmentLength(const uint index) const;

	/** 获取子段数据。
	*/
	uint getSubsegment(char* data, const uint index) const;
	/** 获取子段数据。
	*/
	uint getSubsegment(byte* data, const uint index) const;

	/** 在数据区追加子段数据。
	*/
	uint appendSubsegment(const byte* data, const uint length);
	/** 在数据区追加子段数据。
	*/
	uint appendSubsegment(const char* data, const uint length);

	/** 移除指定索引处的子段数据。
	*/
	void removeSubsegment(const uint index);

	/** 返回标签段长度。
	*/
	inline uint getTagSegmentLength(void) const { return PSL_TAG; }
	/** 返回版本段长度。
	*/
	inline uint getVersionSegmentLength(void) const { return PSL_VERSION; }
	/** 返回序列号段长度。
	*/
	inline uint getSequenceNumberSegmentLength(void) const { return PSL_SN; }
	/** 返回数据区段长度。
	*/
	inline uint getBodyLengthSegmentLength(void) const { return PSL_BODY_LENGTH; }

	/** 返回包总长度。
	*/
	inline uint getTotalLength(void) const { return PSL_TAG + PSL_VERSION + PSL_SN + PSL_BODY_LENGTH + getBodyLength(); }

public:
	/** 打包。
	@return
		返回数据包的完整数据长度。
	*/
	static uint pack(char* output, const Packet* input);
	static uint pack(byte* output, const Packet* input);

	/** 解包。
	*/
	static bool unpack(Packet* output, const char* input, const uint len);
	static bool unpack(Packet* output, const byte* input, const uint len);

private:
	/**
	*/
	void formatNumber(char* output, uint num, uint numlen);

	/**
	*/
	uint resolveBuffSize(const uint currentSize, const uint minimumSize);

private:
	char mTag[PSL_TAG + 1];
	char mVersion[PSL_VERSION + 1];
	char mSequenceNumber[PSL_SN + 1];
	char mBodyLengthSegment[PSL_BODY_LENGTH + 1];
	char* mBody;
	uint mBodyLength;
	uint mBodyBuffLength;
	mutable uint mSegmentNum;
};

/** @} */
/** @} */
} // end namespace cell

#endif // CellPacket_h
